package cn.edu.cuc.yjsy.report;

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.eclipse.core.runtime.IPath;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.xmi.XMIResource;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl;
import cn.edu.cuc.yjsy.report.impl.ReportPackageImpl;

public class ReportModelManager {
	/**
	 * In EMF, a resource provides the way to have access to the model content.
	 */
	private Resource resource = null;

	/**
	 * Contains the factory associated with the model.
	 */
	private static ReportFactory reportFactory = null;

	/**
	 * Gives access to the top level database contained in the resource.
	 */
	private ReportRoot root = null;
	
	/**
	 * Returns the resource containing the report. Uses lazy initialization.
	 * @param path
	 * @return
	 */
	public Resource getResource(IPath path) {
		if (resource == null) {
			ResourceSet resSet = getResourceSet();
			resource =
				resSet.getResource(
					URI.createFileURI(path.toString()),
					true);
		}
		return resource;
	}
	
	/**
	 * Returns the resource containing the report. Throw a runtime exception 
	 * if the resource does not exist.
	 * @param path
	 * @return
	 */
	public Resource getResource() {
		if (resource == null) {
			throw new RuntimeException("Ressource supposed to be already created");
		}
		return resource;
	}
	
	/**
	 * Creates a resource to contain the report. The resource file does not exist yet.
	 * @param path
	 * @return
	 */
	private Resource createResource(IPath path) {
		if (resource == null) {
			ResourceSet resSet = getResourceSet();
			resource =
				resSet.createResource(URI.createURI(path.toString()));
		}
		return resource;
	}
	
	/**
	 * Returns the resource set.
	 * @param 
	 * @return
	 */
	private ResourceSet getResourceSet() {
		// Initialize the report package
		ReportPackageImpl.init();
		// Register the XMI resource factory for the .xml extension
		Resource.Factory.Registry reg = Resource.Factory.Registry.INSTANCE;
		Map m = reg.getExtensionToFactoryMap();
		m.put("report", new XMIResourceFactoryImpl());
		// Obtain a new resource set
		return new ResourceSetImpl();
	}
	
	/**
	 * Returns the factory associated with the model.
	 * Object creation are made through that factory.
	 * @return
	 */
	static public ReportFactory getFactory() {
		if (reportFactory == null) {
			// Access the factory (needed to create instances)
			Map registry = EPackage.Registry.INSTANCE;
			String reportURI = ReportPackage.eNS_URI;
			ReportPackage reportPackage =
				(ReportPackage) registry.get(reportURI);
			reportFactory = reportPackage.getReportFactory();
		}
		return reportFactory;
	}
	
	/**
	 * Loads the content of the model from the file.
	 * @param path
	 */
	public void load(IPath path) throws IOException {
		getResource(path);
		Map options = new HashMap();
		options.put(XMIResource.OPTION_DECLARE_XML, Boolean.TRUE);
		resource.load(options);
	}

    /**
     * reloads the content of the model from the file.
     * @param path
     */
    public void reload(IPath path) throws IOException {
        getResource(path).unload();
        load(path);
    }

	/**
	 * Saves the content of the model to the file.
	 * @param path
	 */
	public void save(IPath path) throws IOException {
		// TODO: Nothing is done of the path if the resource already exist...
		// A second save() method with no argument should be added.
		getResource(path);
		Map options = new HashMap();
		options.put(XMIResource.OPTION_DECLARE_XML, Boolean.TRUE);
		resource.save(options);
	}

	/**
	 * Creates a new report.
	 * @param 
	 * @return
	 */
	public ReportRoot createReport(IPath path) {
		createResource(path);
		// Create a new workflow model
		Map registry = EPackage.Registry.INSTANCE;
		String reportURI = ReportPackage.eNS_URI;
		ReportPackage rpPackage = (ReportPackage) registry.get(reportURI);
		ReportFactory rpFactory = rpPackage.getReportFactory();
		root = rpFactory.createReportRoot();
		resource.getContents().add(root);
		return root;
	}
	
	/**
	 * Gets the top level report model.
	 * @return
	 */
	public ReportRoot getModel() {
		if (null == root) {
			EList l = resource.getContents();
			Iterator i = l.iterator();
			while (i.hasNext()) {
				Object o = i.next();
				if (o instanceof ReportRoot)
					root = (ReportRoot) o;
			}
		}
		return root;
	}

	public void save() throws IOException {
		Map options = new HashMap();
		options.put(XMIResource.OPTION_DECLARE_XML, Boolean.TRUE);
		options.put(XMIResource.OPTION_ENCODING, "UTF-8");
		if(resource != null)
			resource.save(options);
	}
}
